import socket, sys, os, django

sys.path.append("/Volumes/mobile/code/mine/guanxian/ht_guangxian/")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cate.settings")
django.setup()

import django.utils.timezone as timezone
from device.models import temperatureInfo, channelInfo, warningDeviceInfo, deviceInfo, warningSettingInfo

g_conn_pool = []
# 缓存用于存储未完全解析的数据
this_message = ''

def parseMessageTrace(msg):
    if msg[-2:] != '55':
        return ''

    prefix_map = {
        'AA7B07AFEC6648C5': 'temperature',
        'A67B07AFEC6648C5': 'constant',
        'BC7B07AFEC6648C5': 'offline',
        'A57B07AFEC6648C5': 'poor'
    }
    data_type_temp = prefix_map.get(msg[:16], '')
    data_length_temp = msg[20:22] + msg[18:20]
    data_length = int(data_length_temp, 16)
    actual_length = len(msg)/2
    data_type = '' if data_length != actual_length else data_type_temp

    return data_type

def handleTemperatureData(tongdao_temp, hex_str, start_value):
    chunks = [hex_str[i:i+4] for i in range(0, len(hex_str), 4)]
    reversed_chunks = []
    temperatureList = []
    warningList = []

    channelData = channelInfo.objects.get(id=tongdao_temp)
    warningData = warningSettingInfo.objects.get(belong_channel__id=tongdao_temp)

    is_warning = True if warningData.is_constant_threshold == 1 else False
    warning_start_address = 0
    warning_end_address = 0
    warning_constant_value = 0
    if warningData.is_constant_threshold == 1:
        warning_start_address = float(warningData.meter_start)
        warning_end_address = float(warningData.meter_end)
        warning_constant_value = float(warningData.constant_threshold)

    for chunk in chunks:
        this_data = {}
        part1 = chunk[:2]
        part2 = chunk[2:]
        reversed_chunk = part2 + part1

        decimal_value = (int(reversed_chunk, 16)-20000)/100
        this_data['meter'] = start_value
        this_data['temperature'] = decimal_value
        if decimal_value > 0:
            temperatTemp = temperatureInfo(
                belong_channel=channelData, meter_address=start_value, temperature_info=decimal_value, order_time=timezone.now(),
            )
            temperatureList.append(temperatTemp)
        if is_warning == True and start_value >= warning_start_address and start_value <= warning_end_address and decimal_value > warning_constant_value:
            temperatTemp = warningDeviceInfo(
                belong_channel=channelData, meter_address=start_value, temperature_info=decimal_value, order_time=timezone.now(),
                warning_type = 'constant'
            )
            warningList.append(temperatTemp)

        start_value += 0.5
        reversed_chunks.append(this_data)

    is_valid = 1 if reversed_chunks[5]['temperature'] > 0 else 0
    channelInfo.objects.filter(id=tongdao_temp).update(is_valid=is_valid)
    temperatureInfo.objects.bulk_create(temperatureList)

    if len(warningList) > 0:
        warningDeviceInfo.objects.bulk_create(warningList)
    return reversed_chunks


def handleOfflineData(tongdao_temp, hex_str):
    part1 = hex_str[:2]
    part2 = hex_str[2:]
    reversed_chunk = part2 + part1
    decimal_value = int(reversed_chunk, 16)
    channelData = channelInfo.objects.get(id=tongdao_temp)
    warning_res = warningDeviceInfo.objects.create(
        belong_channel=channelData,
        warning_type='offline',
        meter_address=decimal_value,
        order_time=timezone.now()
    )
    return warning_res

def handleWarningData(check_type, tongdao_temp, hex_str):
    channelData = channelInfo.objects.get(id=tongdao_temp)
    warning_type = 'constant' if check_type == 'constant' else 'different'
    groups = [hex_str[i:i+8] for i in range(0, len(hex_str), 8)]
    processed_groups = []
    waringinfoList = []
    for group in groups:
        this_temp_data = {}
        subgroups = [group[i:i+4] for i in range(0, len(group), 4)]
        part1 = subgroups[0][:2]
        part2 = subgroups[0][2:]
        warning_address_temp = part2 + part1
        warning_address = int(warning_address_temp,16)/2
        this_temp_data['warning_address'] = warning_address
        part3 = subgroups[1][:2]
        part4 = subgroups[1][2:]

        warning_value_temp = part4 + part3
        warning_value = int(warning_value_temp, 16)/10
        this_temp_data['warning_value'] = warning_value
        processed_groups.append(this_temp_data)
        if warning_value > 0:
            waringinfoTemp = warningDeviceInfo(
                belong_channel=channelData,
                warning_type=warning_type,
                meter_address=warning_address,
                temperature_info=warning_value,
                order_time=timezone.now()
            )
            waringinfoList.append(waringinfoTemp)
    warningDeviceInfo.objects.bulk_create(waringinfoList)
    return processed_groups

if __name__ == "__main__":
    device_res = deviceInfo.objects.get(id=1)
    this_ip = device_res.ip_address
    this_port = int(device_res.port)
    print('this_port:', this_ip, this_port)
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((this_ip, this_port))
    print('开始接收客户端传过来的数据......')
    try:
        while True:
            message_bytes = client.recv(20000)
            if not message_bytes:
                client.close()
                g_conn_pool.remove(client)
                break

            message_str_temp = message_bytes.hex().upper()
            this_message += message_str_temp
            # print(f'Received message from client: {this_message}')

            while this_message:
                # 校验数据的有效性
                checkRes = parseMessageTrace(this_message)
                # 处理解析数据
                if checkRes:
                    if checkRes == 'temperature':
                        start_temp = this_message[30:34]
                        start_value = int(start_temp[2:] + start_temp[:2], 16)
                        end_temp = this_message[34:38]
                        end_value = int(end_temp[2:] + end_temp[:2], 16)

                        tongdao_temp = this_message[42:44]
                        sys_tongdao_temp =  int(tongdao_temp) + 1
                        data_temp = this_message[44:-2]
                        print('temperature:', sys_tongdao_temp, checkRes, start_value, end_value, timezone.now() )
                        this_data = handleTemperatureData(sys_tongdao_temp, data_temp, start_value)
                        this_message = ''
                        # print('temperature data:', sys_tongdao_temp, this_data)
                    elif checkRes == 'offline':
                        # print('offline_data:', message_bytes)
                        tongdao_temp = this_message[22:24]
                        sys_tongdao_temp =  int(tongdao_temp) + 1
                        data_temp = this_message[24:-2]
                        print('offline:', sys_tongdao_temp, checkRes, start_value, end_value, timezone.now() )
                        this_data = handleOfflineData(sys_tongdao_temp, data_temp)
                        this_message = ''
                        # print('offline data:', sys_tongdao_temp, this_data)
                    elif checkRes == 'poor' or checkRes == 'constant':
                        # print('warning_data:', message)
                        total_warning_temp = this_message[22:24]
                        sys_total_warning_temp =  int(tongdao_temp)
                        tongdao_temp = this_message[24:26]
                        sys_tongdao_temp =  int(tongdao_temp) + 1
                        data_temp = this_message[28:-2]
                        print('constant:', sys_tongdao_temp, checkRes, start_value, end_value, timezone.now() )
                        this_data = handleWarningData(checkRes, sys_tongdao_temp, data_temp)
                        this_message = ''
                        # print('warning_temp_data:', sys_tongdao_temp, this_data)
                else:
                    break

    except socket.error as e:
        print(f'Error in client connection: {e}')
    finally:
        client.close()